{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "from nltk.corpus import stopwords\n",
    "from sklearn.metrics.pairwise import linear_kernel\n",
    "from sklearn.feature_extraction.text import CountVectorizer\n",
    "from sklearn.feature_extraction.text import TfidfVectorizer\n",
    "from sklearn.decomposition import LatentDirichletAllocation\n",
    "pd.options.display.max_columns = 30\n",
    "\n",
    "import warnings\n",
    "\n",
    "warnings.filterwarnings('ignore')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>name</th>\n",
       "      <th>address</th>\n",
       "      <th>desc</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Hilton Garden Seattle Downtown</td>\n",
       "      <td>1821 Boren Avenue, Seattle Washington 98101 USA</td>\n",
       "      <td>Located on the southern tip of Lake Union, the...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Sheraton Grand Seattle</td>\n",
       "      <td>1400 6th Avenue, Seattle, Washington 98101 USA</td>\n",
       "      <td>Located in the city's vibrant core, the Sherat...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Crowne Plaza Seattle Downtown</td>\n",
       "      <td>1113 6th Ave, Seattle, WA 98101</td>\n",
       "      <td>Located in the heart of downtown Seattle, the ...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Kimpton Hotel Monaco Seattle</td>\n",
       "      <td>1101 4th Ave, Seattle, WA98101</td>\n",
       "      <td>What?s near our hotel downtown Seattle locatio...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>The Westin Seattle</td>\n",
       "      <td>1900 5th Avenue, Seattle, Washington 98101 USA</td>\n",
       "      <td>Situated amid incredible shopping and iconic a...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                             name  \\\n",
       "0  Hilton Garden Seattle Downtown   \n",
       "1          Sheraton Grand Seattle   \n",
       "2   Crowne Plaza Seattle Downtown   \n",
       "3   Kimpton Hotel Monaco Seattle    \n",
       "4              The Westin Seattle   \n",
       "\n",
       "                                           address  \\\n",
       "0  1821 Boren Avenue, Seattle Washington 98101 USA   \n",
       "1   1400 6th Avenue, Seattle, Washington 98101 USA   \n",
       "2                  1113 6th Ave, Seattle, WA 98101   \n",
       "3                   1101 4th Ave, Seattle, WA98101   \n",
       "4   1900 5th Avenue, Seattle, Washington 98101 USA   \n",
       "\n",
       "                                                desc  \n",
       "0  Located on the southern tip of Lake Union, the...  \n",
       "1  Located in the city's vibrant core, the Sherat...  \n",
       "2  Located in the heart of downtown Seattle, the ...  \n",
       "3  What?s near our hotel downtown Seattle locatio...  \n",
       "4  Situated amid incredible shopping and iconic a...  "
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "file = './Seattle_Hotels.csv'\n",
    "df = pd.read_csv(file, encoding='latin-1')\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "152"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(df)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "def print_desc(index):\n",
    "    desc = df[df.index == index][['name','desc']].values[0]\n",
    "    if len(desc) >  0:\n",
    "        print('name:',desc[0])\n",
    "        print('desc:',desc[1])\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "name: W Seattle\n",
      "desc: Soak up the vibrant scene in the Living Room Bar and get in the mix with our live music and DJ series before heading to a memorable dinner at TRACE. Offering inspired seasonal fare in an award-winning atmosphere, it's a not-to-be-missed culinary experience in downtown Seattle. Work it all off the next morning at FIT®, our state-of-the-art fitness center before wandering out to explore many of the area's nearby attractions, including Pike Place Market, Pioneer Square and the Seattle Art Museum. As always, we've got you covered during your time at W Seattle with our signature Whatever/Whenever® service - your wish is truly our command.\n"
     ]
    }
   ],
   "source": [
    "print_desc(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([['W Seattle',\n",
       "        \"Soak up the vibrant scene in the Living Room Bar and get in the mix with our live music and DJ series before heading to a memorable dinner at TRACE. Offering inspired seasonal fare in an award-winning atmosphere, it's a not-to-be-missed culinary experience in downtown Seattle. Work it all off the next morning at FIT®, our state-of-the-art fitness center before wandering out to explore many of the area's nearby attractions, including Pike Place Market, Pioneer Square and the Seattle Art Museum. As always, we've got you covered during your time at W Seattle with our signature Whatever/Whenever® service - your wish is truly our command.\"]],\n",
       "      dtype=object)"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df[df.index ==10][['name', 'desc']].values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_top_n_words(corpus, n=1, k=None):\n",
    "    # 统计ngram词频矩阵\n",
    "    cv = CountVectorizer(ngram_range=(n, n), stop_words='english') \n",
    "    # 设置停用词，设为english将使用内置的英语停用词，设为一个list可自定义停用词，设为None不使用停用词，设为None且max_df∈[0.7, 1.0)将自动根据当前的语料库建立停用词表\n",
    "    cv_fit = cv.fit(corpus)\n",
    "    '''\n",
    "    print(cv_fit.get_features_names())\n",
    "    '''\n",
    "    cv_transform = cv_fit.transform(corpus)\n",
    "    sum_words = cv_transform.sum(axis=0)\n",
    "    words_freq = [(word, sum_words[0, idx]) for word, idx in cv_fit.vocabulary_.items()]\n",
    "    words_freq = sorted(words_freq, key= lambda x: x[1], reverse=True)\n",
    "    return words_freq[:k]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[('pike place market', 85), ('seattle tacoma international', 21), ('tacoma international airport', 21), ('free wi fi', 19), ('washington state convention', 17), ('seattle art museum', 16), ('place market seattle', 16), ('state convention center', 15), ('high speed internet', 14), ('space needle pike', 12), ('needle pike place', 11), ('south lake union', 11), ('downtown seattle hotel', 10), ('sea tac airport', 10), ('home away home', 9), ('heart downtown seattle', 8), ('link light rail', 8), ('free high speed', 8), ('just minutes away', 8), ('24 hour fitness', 7)]\n"
     ]
    }
   ],
   "source": [
    "# df_desc = df['desc']\n",
    "common_words = get_top_n_words(df['desc'], 3, 20)\n",
    "print(common_words)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.axes._subplots.AxesSubplot at 0x1ef99438d60>"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "df = pd.DataFrame(common_words, columns=['desc', 'count'])\n",
    "df.groupby('desc').sum()['count'].sort_values().plot(kind='barh', title='去掉停用词后， 描述酒店的Top20单词')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "\n",
    "df1 = pd.DataFrame(common_words, columns = ['desc' , 'count'])\n",
    "df1.groupby('desc').sum()['count'].sort_values().plot(kind='barh', title='去掉停用词后，酒店描述中的Top20单词')\n",
    "plt.show()\n",
    "\n",
    "# 文本预处理\n",
    "REPLACE_BY_SPACE_RE = re.compile('[/(){}\\[\\]\\|@,;]')\n",
    "BAD_SYMBOLS_RE = re.compile('[^0-9a-z #+_]')\n",
    "STOPWORDS = set(stopwords.words('english'))\n",
    "# 对文本进行清洗\n",
    "def clean_text(text):\n",
    "    # 全部小写\n",
    "    text = text.lower()\n",
    "    # 用空格替代一些特殊符号，如标点\n",
    "    text = REPLACE_BY_SPACE_RE.sub(' ', text)\n",
    "    # 移除BAD_SYMBOLS_RE\n",
    "    text = BAD_SYMBOLS_RE.sub('', text)\n",
    "    # 从文本中去掉停用词\n",
    "    text = ' '.join(word for word in text.split() if word not in STOPWORDS) \n",
    "    return text\n",
    "# 对desc字段进行清理\n",
    "df['desc_clean'] = df['desc'].apply(clean_text)\n",
    "#print(df['desc_clean'])\n",
    "\n",
    "# 建模\n",
    "df.set_index('name', inplace = True)\n",
    "# 使用TF-IDF提取文本特征\n",
    "tf = TfidfVectorizer(analyzer='word', ngram_range=(1, 3), min_df=0.01, stop_words='english')\n",
    "\n",
    "tfidf_matrix = tf.fit_transform(df['desc_clean'])\n",
    "print('TFIDF feature names:')\n",
    "#print(tf.get_feature_names())\n",
    "print(len(tf.get_feature_names()))\n",
    "#print('tfidf_matrix:')\n",
    "#print(tfidf_matrix)\n",
    "#print(tfidf_matrix.shape)\n",
    "# 计算酒店之间的余弦相似度（线性核函数）\n",
    "cosine_similarities = linear_kernel(tfidf_matrix, tfidf_matrix)\n",
    "#print(cosine_similarities)\n",
    "#print(cosine_similarities.shape)\n",
    "indices = pd.Series(df.index) #df.index是酒店名称\n",
    "\n",
    "# 基于相似度矩阵和指定的酒店name，推荐TOP10酒店\n",
    "def recommendations(name, cosine_similarities = cosine_similarities):\n",
    "    recommended_hotels = []\n",
    "    # 找到想要查询酒店名称的idx\n",
    "    idx = indices[indices == name].index[0]\n",
    "    print('idx=', idx)\n",
    "    # 对于idx酒店的余弦相似度向量按照从大到小进行排序\n",
    "    score_series = pd.Series(cosine_similarities[idx]).sort_values(ascending = False)\n",
    "    # 取相似度最大的前10个（除了自己以外）\n",
    "    top_10_indexes = list(score_series.iloc[1:11].index)\n",
    "    # 放到推荐列表中\n",
    "    for i in top_10_indexes:\n",
    "        recommended_hotels.append(list(df.index)[i])\n",
    "    return recommended_hotels\n",
    "print(recommendations('Hilton Seattle Airport & Conference Center'))\n",
    "print(recommendations('The Bacon Mansion Bed and Breakfast'))\n",
    "#print(result)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
